package com.wonder.admin.tools;


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wonder.tools.constants.MySqlKeywords;
import com.wonder.tools.model.ModuleInfo;
import com.wonder.admin.config.GenProperties;
import com.wonder.admin.domain.SysAction;
import com.wonder.admin.domain.SysApi;
import com.wonder.admin.domain.SysField;
import com.wonder.admin.domain.SysMenu;
import com.wonder.admin.service.SysActionService;
import com.wonder.admin.service.SysApiService;
import com.wonder.admin.service.SysFieldService;
import com.wonder.admin.service.SysMenuService;
import com.wonder.common.constants.Constants;
import com.wonder.common.utils.StringUtils;

import lombok.extern.java.Log;

@Service
@Log
public class GeneratorService {

	

	@Autowired
	private SysMenuService sysMenuService;

	@Autowired
	private SysActionService sysActionService;

	@Autowired
	private SysFieldService sysFieldService;
	
	@Autowired
	private GenProperties genProperties;
	
	@Autowired
	SysApiService sysApiService;

	// 路径信息
	private String ENTITY = "entity";
	private String VO = "vo";
	private String DAO = "dao";
	private String MAPPER = "mapper";
	private String SERVICE = "service";
	private String SERVICE_IMPL = "serviceImpl";
	private String CONTROLLER = "controller";
	private String API_CONTROLLER = "apicontroller";
	private String REQUEST = "request";


	// 路径信息，分开路径方便聚合工程项目，微服务项目
	private String ENTITY_URL_APPEND = ".{1}.domain";
	private String DAO_URL_APPEND  = ".{1}.mapper";
	private String SERVICE_URL_APPEND  = ".{1}.service";
	private String SERVICE_IMPL_URL_APPEND  = ".{1}.service.impl";
	private String CONTROLLER_URL_APPEND  = ".{1}.controller";
	private String APICONTROLLER_URL_APPEND  = ".api.controller";
	private String VO_URL_APPEND  = ".{1}.vo";
	private String REQUEST_URL_APPEND  = ".{1}.request";
	// 路径信息，分开路径方便聚合工程项目，微服务项目
	private String ENTITY_URL = ".{1}.domain";
	private String DAO_URL = ".{1}.mapper";
	private String XML_URL = "";
	private String SERVICE_URL = ".{1}.service";
	private String SERVICE_IMPL_URL = ".{1}.service.impl";
	private String CONTROLLER_URL = ".{1}.controller";
	private String APICONTROLLER_URL = ".api.controller";
	private String VO_URL = ".{1}.vo";
	private String REQUEST_URL = ".{1}.request";
	
	//生成文件路径
	private String DESTINATION_JAVA_PATH_APPEND= "/src/main/java/";
	private String DESTINATION_JAVA_PATH= "/src/main/java/";
	//生成文件路径
	private String DESTINATION_JAVA_ADMIN_PATH_APPEND= "/src/main/java/";
	private String DESTINATION_JAVA_ADMIN_PATH= "/src/main/java/";
	//生成文件路径
	private String DESTINATION_JAVA_API_PATH_APPEND= "/src/main/java/";
	private String DESTINATION_JAVA_API_PATH= "/src/main/java/";
	//生成文件路径
	private String DESTINATION_JAVA_SERVICE_PATH_APPEND= "/src/main/java/";
	private String DESTINATION_JAVA_SERVICE_PATH= "/src/main/java/";
	//Mapper.xml文件路径
	private String DESTINATION_MAPPER_XML_PATH_APPEND= "/src/main/resources/mapper/{1}/";
	private String DESTINATION_MAPPER_XML_PATH= "/src/main/resources/mapper/{1}/";
	
	//生成VUE API文件路径
	private String DESTINATION_VUE_API_PATH_APPEND= "/src/api/{1}/";
	private String DESTINATION_VUE_API_PATH= "/src/api/{1}/";
	private String DESTINATION_VUE_API_PATH_TEXT= "/src/api/{1}/";
	
	//生成VUE 文件路径
	private String DESTINATION_VUE_PATH_APPEND= "/src/views/{}/{}/";
	private String DESTINATION_VUE_PATH= "/src/views/{}/{}/";
	private String DESTINATION_VUE_PATH_TEXT= "/src/views/{}/{}/";
	
	private String projectDir;
	private String projectAdminDir;
	private String projectServiceDir;
	private String projectApiDir;
	private String projectVueDir;
	
	private ModuleInfo dataModel;
	
	//Initialize the parameters
	public void Initialize(Long menu_id) {
		
		dataModel=getModuleInfo(menu_id);
		projectDir=System.getProperty("user.dir");
		projectVueDir=System.getProperty("user.dir");
		projectApiDir=System.getProperty("user.dir");
		projectServiceDir=System.getProperty("user.dir");
		projectAdminDir=System.getProperty("user.dir");
		
		if(StringUtils.hasText(genProperties.vueProjectDir)) projectVueDir=genProperties.vueProjectDir;
		if(StringUtils.hasText(genProperties.javaProjectDir))projectDir=genProperties.javaProjectDir;
		if(StringUtils.hasText(genProperties.javaApiProjectDir))projectApiDir=genProperties.javaApiProjectDir;
		if(StringUtils.hasText(genProperties.javaAdminProjectDir))projectAdminDir=genProperties.javaAdminProjectDir;
		if(StringUtils.hasText(genProperties.javaServiceProjectDir))projectServiceDir=genProperties.javaServiceProjectDir;
		
		String basePackage=dataModel.getBasePackageName();
		DESTINATION_JAVA_PATH=projectDir+DESTINATION_JAVA_PATH_APPEND;
		DESTINATION_JAVA_SERVICE_PATH=projectServiceDir+DESTINATION_JAVA_SERVICE_PATH_APPEND;
		DESTINATION_JAVA_ADMIN_PATH=projectAdminDir+DESTINATION_JAVA_ADMIN_PATH_APPEND;
		DESTINATION_JAVA_API_PATH=projectApiDir+DESTINATION_JAVA_API_PATH_APPEND;
		
		DESTINATION_MAPPER_XML_PATH=(projectServiceDir+DESTINATION_MAPPER_XML_PATH_APPEND).replace("{1}", dataModel.getMenuInfo().getModule());
		
		DESTINATION_VUE_API_PATH=(projectVueDir+DESTINATION_VUE_API_PATH_APPEND).replace("{1}", dataModel.getMenuInfo().getModule());
		DESTINATION_VUE_API_PATH_TEXT=DESTINATION_VUE_API_PATH_APPEND.replace("{1}", dataModel.getMenuInfo().getModule());
		
		DESTINATION_VUE_PATH=StringUtils.format(projectVueDir+DESTINATION_VUE_PATH_APPEND,dataModel.getMenuInfo().getModule(),dataModel.getEntityName().toLowerCase());
		DESTINATION_VUE_PATH_TEXT=StringUtils.format(DESTINATION_VUE_PATH_APPEND,dataModel.getMenuInfo().getModule(),dataModel.getEntityName().toLowerCase());
		
		ENTITY_URL=basePackage+ENTITY_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		DAO_URL=basePackage+DAO_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		REQUEST_URL=basePackage+REQUEST_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		SERVICE_URL=basePackage+SERVICE_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		SERVICE_IMPL_URL=basePackage+SERVICE_IMPL_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		CONTROLLER_URL=basePackage+CONTROLLER_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		APICONTROLLER_URL=basePackage+APICONTROLLER_URL_APPEND;
		VO_URL=basePackage+VO_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		
		
		dataModel.setEntityUrl(ENTITY_URL);
		dataModel.setDaoUrl(DAO_URL);
		dataModel.setServiceImplUrl(SERVICE_IMPL_URL);
		dataModel.setServiceUrl(SERVICE_URL);
		dataModel.setRequestUrl(REQUEST_URL);
		dataModel.setControllerUrl(CONTROLLER_URL);
		dataModel.setApiControllerUrl(APICONTROLLER_URL);
		dataModel.setVoUrl(VO_URL);
		
		Map<String, String> zipFilePath=new HashMap<String, String>(){{  
			put(MAPPER, JavaFileTextUrl("", XML_URL,dataModel.getEntityName(), MAPPER));  
			put(ENTITY, JavaFileTextUrl("", ENTITY_URL,dataModel.getEntityName(), ENTITY));
			put(VO, JavaFileTextUrl("", VO_URL,dataModel.getEntityName(), VO));
			put(DAO, JavaFileTextUrl("", DAO_URL,dataModel.getEntityName(), DAO));
			put(REQUEST, JavaFileTextUrl("", REQUEST_URL,dataModel.getEntityName(), REQUEST));
			put(SERVICE, JavaFileTextUrl("", SERVICE_URL,dataModel.getEntityName(), SERVICE));
			put(SERVICE_IMPL, JavaFileTextUrl("", SERVICE_IMPL_URL,dataModel.getEntityName(), SERVICE_IMPL));
			put(CONTROLLER, JavaFileTextUrl("", CONTROLLER_URL,dataModel.getEntityName(), CONTROLLER));
			put(API_CONTROLLER, JavaFileUrl("", APICONTROLLER_URL,dataModel.getEntityName(), CONTROLLER));
			put("vue_api",VueFileUrl(DESTINATION_VUE_API_PATH_TEXT, dataModel.getEntityName(), "api") );
			put("vue_view", DESTINATION_VUE_PATH_TEXT);
		}};  
		dataModel.setZipFilePath(zipFilePath);
		
		Map<String, String> FilePath=new HashMap<String, String>(){{  
			put(MAPPER, JavaFileUrl(DESTINATION_MAPPER_XML_PATH, XML_URL,dataModel.getEntityName(), MAPPER));  
			put(ENTITY,  JavaFileUrl(DESTINATION_JAVA_SERVICE_PATH, ENTITY_URL,dataModel.getEntityName(), ENTITY));
			put(VO, JavaFileUrl(DESTINATION_JAVA_SERVICE_PATH, VO_URL,dataModel.getEntityName(), VO));
			put(DAO, JavaFileUrl(DESTINATION_JAVA_SERVICE_PATH, DAO_URL,dataModel.getEntityName(), DAO));
			put(REQUEST,  JavaFileUrl(DESTINATION_JAVA_SERVICE_PATH, REQUEST_URL,dataModel.getEntityName(), REQUEST));
			put(SERVICE, JavaFileUrl(DESTINATION_JAVA_SERVICE_PATH, SERVICE_URL,dataModel.getEntityName(), SERVICE));
			put(SERVICE_IMPL, JavaFileUrl(DESTINATION_JAVA_SERVICE_PATH, SERVICE_IMPL_URL,dataModel.getEntityName(), SERVICE_IMPL));
			put(CONTROLLER, JavaFileUrl(DESTINATION_JAVA_ADMIN_PATH, CONTROLLER_URL,dataModel.getEntityName(), CONTROLLER));
			put(API_CONTROLLER, JavaFileUrl(DESTINATION_JAVA_API_PATH, APICONTROLLER_URL,dataModel.getEntityName(), CONTROLLER));
			put("vue_api",VueFileUrl(DESTINATION_VUE_API_PATH, dataModel.getEntityName(), "api") );
			put("vue_view", projectVueDir);
		}};  
		dataModel.setFilePath(FilePath);
	
	}
	
	/**
	 * For remote source code generate
	 * @param menu
	 * @param actionList
	 * @param fieldList
	 * @param packageName
	 */
    public void Initialize(SysMenu menu,List<SysAction> actionList,List<SysField> fieldList,List<SysApi> apiList,String packageName) {
    	
    	dataModel=getModuleInfo(menu,actionList,fieldList,apiList);
			
		String basePackage=packageName;
		DESTINATION_VUE_API_PATH_TEXT=DESTINATION_VUE_API_PATH_APPEND.replace("{1}", dataModel.getMenuInfo().getModule());
		DESTINATION_VUE_PATH_TEXT=StringUtils.format(DESTINATION_VUE_PATH_APPEND,dataModel.getMenuInfo().getModule(),dataModel.getEntityName().toLowerCase());		
		ENTITY_URL=basePackage+ENTITY_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		DAO_URL=basePackage+DAO_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		REQUEST_URL=basePackage+REQUEST_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		SERVICE_URL=basePackage+SERVICE_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		SERVICE_IMPL_URL=basePackage+SERVICE_IMPL_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		CONTROLLER_URL=basePackage+CONTROLLER_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());
		APICONTROLLER_URL=basePackage+APICONTROLLER_URL_APPEND;
		VO_URL=basePackage+VO_URL_APPEND .replace("{1}", dataModel.getMenuInfo().getModule());

		dataModel.setEntityUrl(ENTITY_URL);
		dataModel.setDaoUrl(DAO_URL);
		dataModel.setServiceImplUrl(SERVICE_IMPL_URL);
		dataModel.setServiceUrl(SERVICE_URL);
		dataModel.setRequestUrl(REQUEST_URL);
		dataModel.setControllerUrl(CONTROLLER_URL);
		dataModel.setApiControllerUrl(APICONTROLLER_URL);
		dataModel.setVoUrl(VO_URL);
	
    	
    }

	
	public  ModuleInfo getDataModel() {
		return this.dataModel;
	}
	

	// 生成文件路径和名字
	private String JavaFileUrl(String url, String packageUrl, String entityName, String type) {
		if (url.equals(""))
			url = System.getProperty("user.dir") + "/src/main/java/";
		if (type.equals("entity")) {
			return url + pageToUrl(packageUrl) + entityName + ".java";
		} else if (type.equals("dao")) {
			return url + pageToUrl(packageUrl) + entityName + "Dao.java";
		} else if (type.equals("mapper")) {
			return url + pageToUrl(packageUrl) + entityName + "Mapper.xml";
		} else if (type.equals("service")) {
			return url + pageToUrl(packageUrl) + entityName + "Service.java";
		} else if (type.equals("serviceImpl")) {
			return url + pageToUrl(packageUrl) + entityName + "ServiceImpl.java";
		} else if (type.equals("controller")) {
			return url + pageToUrl(packageUrl) + entityName + "Controller.java";
		} else if (type.equals("vo")) {
			return url + pageToUrl(packageUrl) + entityName + "Vo.java";
		} else if (type.equals("request")) {
			return url + pageToUrl(packageUrl) + entityName + "Request.java";
		}
		return null;
	}
	
	// 生成文件路径和名字
	private String JavaFileTextUrl(String url, String packageUrl, String entityName, String type) {
			if (url.equals(""))
				url =  "/src/main/java/";
			if (type.equals("entity")) {
				return url + pageToUrl(packageUrl) + entityName + ".java";
			} else if (type.equals("dao")) {
				return url + pageToUrl(packageUrl) + entityName + "Dao.java";
			} else if (type.equals("mapper")) {
				return url + pageToUrl(packageUrl) + entityName + "Mapper.xml";
			} else if (type.equals("service")) {
				return url + pageToUrl(packageUrl) + entityName + "Service.java";
			} else if (type.equals("serviceImpl")) {
				return url + pageToUrl(packageUrl) + entityName + "ServiceImpl.java";
			} else if (type.equals("controller")) {
				return url + pageToUrl(packageUrl) + entityName + "Controller.java";
			} else if (type.equals("vo")) {
				return url + pageToUrl(packageUrl) + entityName + "Vo.java";
			} else if (type.equals("request")) {
				return url + pageToUrl(packageUrl) + entityName + "Request.java";
			}
			return null;
		}
	
	private String VueFileUrl(String url,String entityName,String type) {
		if(type.equals("api")) {
			return url+entityName.toLowerCase()+".js";
		}else {
			return url+type+".vue";
		}
	}

	private String pageToUrl(String url) {
		return url.replace(".", "/") + "/";
	}

	/**
	 * <p>
	 * 说明:获取字段名，把"_"后面字母变大写,第一个字母小写
	 * </p>
	 * 
	 * @param field 字段名
	 * @return String
	 */
	private String changeToJavaField(String field) {
		String[] fields = field.split("_");
		StringBuilder sbuilder = new StringBuilder(fields[0]);
		for (int i = 1; i < fields.length; i++) {
			char[] cs = fields[i].toCharArray();
			cs[0] -= 32;
			sbuilder.append(String.valueOf(cs));
		}
		return sbuilder.toString();
	}

	/**
	 * <p>
	 * 说明:获取模块名，把"_"后面字母变大写,第一个字母大写
	 * </p>
	 * 
	 * @param field 字段名
	 * @return String
	 */
	private String changeToJavaEntity(String field) {
		String[] fields = field.split("_");
		StringBuilder sbuilder = new StringBuilder();
		for (int i = 0; i < fields.length; i++) {
			char[] cs = fields[i].toCharArray();
			cs[0] -= 32;
			sbuilder.append(String.valueOf(cs));
		}
		return sbuilder.toString();
	}

	private ModuleInfo getModuleInfo(SysMenu menu,List<SysAction> actionList,List<SysField> fieldList,List<SysApi> apiList)
	{
		ModuleInfo moduleInfo = new ModuleInfo();

		moduleInfo.setAppFolder(menu.getModule());
		if(menu.getTable_name().equals("sys_config")) moduleInfo.setAppFolder("admin");

		moduleInfo.setRemovePrefix(genProperties.removePrefix);
		moduleInfo.setAuthor(genProperties.author);
		moduleInfo.setBasePackageName(genProperties.basePackageName);
		moduleInfo.setPrefix(genProperties.prefix);
		moduleInfo.setSwagger(genProperties.isSwagger);
		moduleInfo.setVersion(genProperties.version);
		moduleInfo.setProject(genProperties.project);
		moduleInfo.setOverwriteExist(genProperties.overwriteExist);
		moduleInfo.setI118(genProperties.useMultipleLanguage);
		
			
		moduleInfo.setPk(menu.getPk());
		moduleInfo.setActionList(actionList);
		moduleInfo.setFieldList(fieldList);
		moduleInfo.setApiList(apiList);
		
		moduleInfo.setMenuInfo(menu);
		List<Map<String, Object>> columnsList=sysFieldService.getColumnMapList(menu.getTable_name());
		moduleInfo.setTableFields(columnsList);
		List<Map<String, String>> columns=new ArrayList<>();
		List<String> fieldArray=new ArrayList<String>();//Save the field name list from the sys_field table
		String field="";
		for(Map<String, Object> item:columnsList) {
			Map<String, String> map=new HashMap<String, String>();
			String columnName=item.get("COLUMN_NAME").toString();
			for(SysField sysField:fieldList) {
				if(sysField.getField().equals(columnName)) {
					if(!StringUtils.hasText(sysField.getBelong_table()))
					           sysField.set_main_table(true);
				}
			}
			map.put("column", columnName);
			if(field.equals("") ) {
				field=columnName;
			}else {
				field=field+","+columnName;
			}
			columns.add(map);
		}
		//Get the Java type
		for(SysField sysField:fieldList) {
			fieldArray.add(sysField.getField());
			String dataType=sysField.getDatatype();
			if(dataType.equals("decimal") && StringUtils.hasText(sysField.getLength())) {
				if(Integer.parseInt(sysField.getLength()) >12) dataType="bigdecimal";
			}
			sysField.setJavatype(getJavaType(dataType));
			String dropSql=sysField.getSql();
			if(StringUtils.hasText(dropSql)) {
				sysField.setDropDownSql(dropSql.replace("pre_", genProperties.prefix));
			}
			
			if(StringUtils.hasText(sysField.getSql())) moduleInfo.setHaveSql(true);
			sysField.setItem_config(null); //
			 
			 @SuppressWarnings("unchecked")
			List<Map<String, Object>> items = JSON.parseObject(sysField.getItem_config_table(), new ArrayList<Map<String, Object>>().getClass()); 
			 if(items==null || items.size()==0)
			 {
				 sysField.setItem_config(null); //
			 }else {
				 sysField.setItem_config(items);
			}
			 if(sysField.getOther_config_table()!=null) {
				// System.out.print("other config:"+sysField.getOther_config_table()+" field="+sysField.getField());
				 @SuppressWarnings("unchecked")
				 Map<String, Object> other_items = JSON.parseObject(sysField.getOther_config_table(), new HashMap<String, Object>().getClass()); 
				 if(other_items==null || other_items.isEmpty())
				 {
					 sysField.setOther_config(null);//
				 }else {
					 sysField.setOther_config(other_items);
				}
			 }
			 //Post status null ，set it to 0, for freemarker use
			 if(sysField.getPost_status()==null) sysField.setPost_status(0);
			 
			 if(MySqlKeywords.KEYWORDS.contains(sysField.getField().toUpperCase()))
				 sysField.setKeywords(true);
			 
			 if(!StringUtils.hasText(sysField.getShow_condition()))
					 sysField.setShow_condition(null);
			
			 //String[] validate= {""};
			 if(StringUtils.hasText(sysField.getValidate_table())) 
			    sysField.setValidate(StringUtils.splitPreserveAllTokens(sysField.getValidate_table(), ","));
			 else {
				 sysField.setValidate(null);
			}
		}
		
		for(SysApi sysApi:apiList) {
			if(sysApi.getParameters_table()!=null) {
				@SuppressWarnings("unchecked")
				List<Map<String, Object>> parameters = JSON.parseObject(sysApi.getParameters_table(),
						new ArrayList<Map<String, Object>>().getClass());
				sysApi.setParameters(parameters);
			}
		}
		
		//Get the Java type
		List<String> columnsPost = sysFieldService.getFieldList(menu.getMenu_id());
		for(SysAction sysAction:actionList) {
			if (sysAction.getTab_config_table() != null) {
				@SuppressWarnings("unchecked")
				List<Map<String, Object>> tab_config_items = JSON.parseObject(sysAction.getTab_config_table(),
						new ArrayList<Map<String, Object>>().getClass());
				sysAction.setTab_config(tab_config_items);
			}

			if (sysAction.getList_filter_table() != null) {
				@SuppressWarnings("unchecked")
				List<Map<String, Object>> list_filter_items = JSON.parseObject(sysAction.getList_filter_table(),
						new ArrayList<Map<String, Object>>().getClass());
				sysAction.setList_filter(list_filter_items);
			}

			if (sysAction.getWith_join_table() != null) {
				@SuppressWarnings("unchecked")
				List<Map<String, Object>> with_join_items = JSON.parseObject(sysAction.getWith_join_table(),
						new ArrayList<Map<String, Object>>().getClass());
				sysAction.setWith_join(with_join_items);
			}
			String[] field_post = StringUtils.split(sysAction.getFields_table(), ",");
			if (field_post != null && sysAction.getFields_table().length()>2) {
				List<String> fields = Arrays.asList(field_post);
				if (field_post != null && field_post.length > 0) {
					for (String fieldName : field_post) {
						if (!columnsPost.contains(fieldName))
							if(fields.contains(fieldName))fields.remove(fieldName);
					}
					sysAction.setFields(fields.toArray(new String[] {}));
				}
			}else {
				//Set all the fields in the field list
				if(sysAction.getType()==16 || sysAction.getType()==15) {
					sysAction.setFields(new String[0]);
				}else {
				sysAction.setFields(fieldArray.toArray(new String[fieldArray.size()]));
				}
				
			}
			//获取JointSQL
			if(sysAction.getType()==1 && StringUtils.hasText(sysAction.getWith_join_table())) {
				@SuppressWarnings("unchecked")
				List<Map<String, Object>> with_join_items = JSON.parseObject(sysAction.getWith_join_table(),
						new ArrayList<Map<String, Object>>().getClass());
				
				String sql="select ";
				String joinString=" from " +menu.getTable_name()+" a ";
						
				int i=98;
				char alias = (char) i;
				
				List<Map<String, String>> tableList=new ArrayList<Map<String,String>>();
		        for(Map<String, Object> item:sysAction.getWith_join()) {
		        	Map<String, String> tableAlias=new HashMap<String, String>();
		        	item.put("alias", alias);
		        	tableAlias.put("table_name", item.get("table_name").toString());
		        	tableAlias.put("alias", alias+"");
		        	tableList.add(tableAlias);
		        	joinString +=" left join "+item.get("table_name") +" " + alias +" on a." +item.get("fk")+"=" +alias +"."
		        			+item.get("pk");
		        	i++;
		        	alias=(char) i;
		        }
		        moduleInfo.setTableList(tableList);
				for(SysField sysField:fieldList) {
					if(StringUtils.hasText(sysField.getBelong_table())){
						for(Map<String, Object> item:sysAction.getWith_join()) {
							if(item.get("table_name").toString().equals(sysField.getBelong_table())) {
								
								if(sql.equals("select ")) {
									sql +=item.get("alias")+"."+sysField.getField() + " as " 
								        +sysField.getBelong_table().replace(moduleInfo.getPrefix(), "")+"_" + sysField.getField();
								}else {
									sql +=","+item.get("alias")+"."+sysField.getField() + " as " 
									        +sysField.getBelong_table().replace(moduleInfo.getPrefix(), "")+"_" + sysField.getField();
								}
								//For generator entity , to replace the field name with table_name +field name
								sysField.setBelong_column(sysField.getField());//关联表字段
								sysField.setField(sysField.getBelong_table().replace(moduleInfo.getPrefix(), "")+"_" + sysField.getField());
							}
						}
					}else {
						List<Integer> types=Arrays.asList(3,5,14,16,18,21,22,35);
						if(sql.equals("select ")) {
							if(types.contains(sysField.getType())) {
								sql +="a."+sysField.getField()+ " as " +sysField.getField()+"_table";
							}else {
							sql +="a."+sysField.getField();
							}
						}else {
							if(types.contains(sysField.getType())) {
								sql +=",a."+sysField.getField()+ " as " +sysField.getField()+"_table";
							}else {
							sql +=",a."+sysField.getField();
							}
						}
					}
				}
				moduleInfo.setJointSql(sql +"\n       "+joinString);
			}
		}
				
		moduleInfo.setFields(field);
		moduleInfo.setColumns(columns);
		moduleInfo.setFieldArray(fieldArray);
		
		
		moduleInfo.setJoinTableInfo(sysActionService.getExtend(actionList));
		if (moduleInfo.isRemovePrefix()) {
			moduleInfo.setEntityName(moduleInfo.getMenuInfo().getController_name());
		} else {
			moduleInfo.setEntityName(
					changeToJavaEntity(moduleInfo.getPrefix() + moduleInfo.getMenuInfo().getController_name()));
		}
		moduleInfo.setRandomSerial(createId());
		

		return moduleInfo;
		
	}
	private ModuleInfo getModuleInfo(Long menu_id) {

		SysMenu menu = sysMenuService.getById(menu_id);
		List<SysAction> actionList = sysActionService.list(new QueryWrapper<SysAction>().eq("menu_id", menu_id).orderByAsc("sortid"));
		List<SysField> fieldList = sysFieldService.list(new QueryWrapper<SysField>().eq("menu_id", menu_id).orderByAsc("sortid"));
		List<SysApi> apiList=sysApiService.list(new QueryWrapper<SysApi>().eq("menu_id", menu_id).orderByAsc("sortid"));

		if (menu == null)
			return null;
		
		return getModuleInfo(menu, actionList, fieldList,apiList);

	}
	
	
	/**
	 * 随机长整数
	 * @return
	 */
	private  String createId() {
        String a = (String.valueOf(System.currentTimeMillis())).substring(0, 10);
        String d = (String.valueOf(Math.random())).substring(2, 8);
        
        return a + d;
    }
	
	
	
	
	
	
	private String getJavaType( String fieldType) {
	        String t = fieldType.toLowerCase();
	        if (t.contains("char")) {
	            return "String";
	        } else if (t.equals("bigint")) {
	            return "Long";
	        } else if (t.equals("tinyint")) {	
	            return "Integer";
	        } else if (t.equals("smallint")) {	
	            return "Integer";    
	        } else if (t.equals("int")) {
	            return "Long";
	        } else if (t.contains("text")) {
	            return "String";
	        } else if (t.contains("bit")) {
	            return "Boolean";
	        } else if (t.contains("bigdecimal")) {
	            return "BigDecimal";
	        } else if (t.contains("decimal")) {
	            return "Double";   
	        } else if (t.contains("binary")) {
	            return "byte[]";
	        } else if (t.contains("float")) {
	            return "Double";
	        } else if (t.contains("double")) {
	            return "Double";
	        } else if (t.contains("timestamp")) {
	            return "Date";
	        } else if (t.contains("datetime")) {
	            return "Date"; 
	        } else if (t.contains("date")) {
	            return "Date";     
	        } else if (t.contains("time")) {
	            return "Date";       
	        
	        }

	        return "String";
	    }

	//Write code to project
	public void writeCode(Map<String, String> data,ModuleInfo dataModel) {
		Map<String, String> fullFilePath=dataModel.getFilePath();
		Map<String, String> zipFilePath=dataModel.getZipFilePath();
		Set<String> set = fullFilePath.keySet();
		for (String o : set) {
		   String path=fullFilePath.get(o);
		   String zipPath=zipFilePath.get(o);
		  
		   if(!o.equals("vue_view")) {
			   String code=data.get(zipPath);
			   if(StringUtils.hasText(code)) {
				    try {
				    	File file = new File(path);
						if (!file.getParentFile().exists()) {
							file.getParentFile().mkdirs();
						}
				     FileWriter writer = new FileWriter(path);
				      writer.write(code);
				      writer.flush();
				      writer.close();
				    } catch (IOException e) {
				      e.printStackTrace();
				    }
			   }
		  }else {
			  Set<String> setCode = data.keySet(); 
			  for (String zipFile : setCode) {
				  if(zipFile.substring(zipFile.length() - 4).equals(".vue")) {
					  String newPath=path+zipFile;
					  String code=data.get(zipFile);
					  if(StringUtils.hasText(code)) {
						    try {
						    	File file = new File(newPath);
								if (!file.getParentFile().exists()) {
									file.getParentFile().mkdirs();
								}
						     FileWriter writer = new FileWriter(newPath);
						      writer.write(code);
						      writer.flush();
						      writer.close();
						    } catch (IOException e) {
						      e.printStackTrace();
						    }
					   }
					  
				  }
			  }
			  
		  }
		}
		
	}
	
	//Write code to project
	public byte[] downloadCode(Map<String, String> data,ModuleInfo dataModel) {

			Map<String, String> zipFilePath=dataModel.getZipFilePath();
			Set<String> set = zipFilePath.keySet();
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		    ZipOutputStream zip = new ZipOutputStream(outputStream);
			for (String o : set) {
			   String zipPath=zipFilePath.get(o);
			   String code=data.get(zipPath);
			   if(StringUtils.hasText(code)) {
	
				       writeToZip(zipPath, code, zip);

			   }
			}
			IOUtils.closeQuietly(zip);
		    return outputStream.toByteArray();
			
	}
	
	private void writeToZip(String path,String value,ZipOutputStream zip) {
    	if(!StringUtils.hasText(path)) return;
    	  try
          {
              // 添加到zip
              zip.putNextEntry(new ZipEntry(path));
              IOUtils.write(value, zip, Constants.UTF8);
             // IOUtils.C
			  zip.flush();
              zip.closeEntry();
          }
          catch (IOException e)
          {
              log.warning("渲染模板文件保存到zip失败：" + path);
          }
    }
	
	

}
